package co.pushmall.modules.shop.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import co.pushmall.enums.OrderInfoEnum;
import co.pushmall.exception.BadRequestException;
import co.pushmall.exception.EntityExistException;
import co.pushmall.modules.activity.domain.PushMallStorePink;
import co.pushmall.modules.activity.repository.PushMallStorePinkRepository;
import co.pushmall.modules.shop.domain.PushMallStoreOrder;
import co.pushmall.modules.shop.domain.PushMallStoreOrderStatus;
import co.pushmall.modules.shop.domain.PushMallUserBill;
import co.pushmall.modules.shop.domain.StoreOrderCartInfo;
import co.pushmall.modules.shop.domain.PushMallStoreProductAttrValue;
import co.pushmall.modules.shop.repository.PushMallStoreCartRepository;
import co.pushmall.modules.shop.repository.PushMallStoreOrderCartInfoRepository;
import co.pushmall.modules.shop.repository.PushMallStoreOrderRepository;
import co.pushmall.modules.shop.repository.PushMallStoreProductAttrValueRepository;
import co.pushmall.modules.shop.repository.PushMallStoreProductRepository;
import co.pushmall.modules.shop.repository.PushMallUserRepository;
import co.pushmall.modules.shop.service.PushMallStoreOrderService;
import co.pushmall.modules.shop.service.PushMallStoreOrderStatusService;
import co.pushmall.modules.shop.service.PushMallSystemStoreService;
import co.pushmall.modules.shop.service.PushMallUserBillService;
import co.pushmall.modules.shop.service.PushMallUserService;
import co.pushmall.modules.shop.service.dto.CountDto;
import co.pushmall.modules.shop.service.dto.OrderCountDto;
import co.pushmall.modules.shop.service.dto.OrderTimeDataDTO;
import co.pushmall.modules.shop.service.dto.StoreOrderCartInfoDTO;
import co.pushmall.modules.shop.service.dto.PushMallStoreOrderDTO;
import co.pushmall.modules.shop.service.dto.PushMallStoreOrderQueryCriteria;
import co.pushmall.modules.shop.service.dto.PushMallUserDTO;
import co.pushmall.modules.shop.service.mapper.PushMallStoreOrderMapper;
import co.pushmall.mp.service.PushMallMiniPayService;
import co.pushmall.mp.service.PushMallPayService;
import co.pushmall.utils.FileUtil;
import co.pushmall.utils.OrderUtil;
import co.pushmall.utils.QueryHelp;
import co.pushmall.utils.ValidationUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.binarywang.wxpay.exception.WxPayException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * @author pushmall
 * @date 2019-10-14
 */
@Slf4j
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class PushMallStoreOrderServiceImpl implements PushMallStoreOrderService {

    private final PushMallStoreOrderRepository pushMallStoreOrderRepository;
    private final PushMallStoreOrderCartInfoRepository pushMallStoreOrderCartInfoRepository;
    private final PushMallUserRepository userRepository;
    private final PushMallStorePinkRepository storePinkRepository;
    private final PushMallStoreProductRepository storeProductRepository;
    private final PushMallStoreCartRepository pushMallStoreCartRepository;
    private final PushMallStoreProductAttrValueRepository pushMallStoreProductAttrValueRepository;

    private final PushMallStoreOrderMapper pushMallStoreOrderMapper;

    private final PushMallUserBillService pushMallUserBillService;
    private final PushMallStoreOrderStatusService pushMallStoreOrderStatusService;
    private final PushMallUserService userService;
    private final PushMallPayService payService;
    private final PushMallMiniPayService miniPayService;
    private final PushMallSystemStoreService systemStoreService;

    public PushMallStoreOrderServiceImpl(PushMallStoreOrderRepository pushMallStoreOrderRepository, PushMallStoreOrderCartInfoRepository pushMallStoreOrderCartInfoRepository, PushMallUserRepository userRepository,
                                         PushMallStorePinkRepository storePinkRepository, PushMallStoreOrderMapper pushMallStoreOrderMapper, PushMallUserBillService pushMallUserBillService,
                                         PushMallStoreOrderStatusService pushMallStoreOrderStatusService, PushMallSystemStoreService systemStoreService, PushMallStoreCartRepository pushMallStoreCartRepository,
                                         PushMallUserService userService, PushMallPayService payService, PushMallMiniPayService miniPayService, PushMallStoreProductRepository storeProductRepository,
                                         PushMallStoreProductAttrValueRepository pushMallStoreProductAttrValueRepository) {
        this.pushMallStoreOrderRepository = pushMallStoreOrderRepository;
        this.pushMallStoreOrderCartInfoRepository = pushMallStoreOrderCartInfoRepository;
        this.userRepository = userRepository;
        this.storePinkRepository = storePinkRepository;
        this.pushMallStoreOrderMapper = pushMallStoreOrderMapper;
        this.pushMallUserBillService = pushMallUserBillService;
        this.pushMallStoreOrderStatusService = pushMallStoreOrderStatusService;
        this.userService = userService;
        this.payService = payService;
        this.miniPayService = miniPayService;
        this.systemStoreService = systemStoreService;
        this.storeProductRepository = storeProductRepository;
        this.pushMallStoreCartRepository = pushMallStoreCartRepository;
        this.pushMallStoreProductAttrValueRepository = pushMallStoreProductAttrValueRepository;
    }

    @Override
    public OrderCountDto getOrderCount() {
        //获取所有订单转态为已支付的
        List<CountDto> nameList = pushMallStoreCartRepository.findCateName();
        System.out.println("nameList:" + nameList);
        Map<String, Integer> childrenMap = new HashMap<>();
        nameList.forEach(i -> {
            if (i != null) {
                if (childrenMap.containsKey(i.getCatename())) {
                    childrenMap.put(i.getCatename(), childrenMap.get(i.getCatename()) + 1);
                } else {
                    childrenMap.put(i.getCatename(), 1);
                }
            }

        });
        List<OrderCountDto.OrderCountData> list = new ArrayList<>();
        List<String> columns = new ArrayList<>();
        childrenMap.forEach((k, v) -> {
            OrderCountDto.OrderCountData orderCountData = new OrderCountDto.OrderCountData();
            orderCountData.setName(k);
            orderCountData.setValue(v);
            columns.add(k);
            list.add(orderCountData);
        });
        OrderCountDto orderCountDto = new OrderCountDto();
        orderCountDto.setColumn(columns);
        orderCountDto.setOrderCountDatas(list);
        return orderCountDto;
    }

    @Override
    public OrderTimeDataDTO getOrderTimeData() {
        int today = OrderUtil.dateToTimestampT(DateUtil.beginOfDay(new Date()));
        int yesterday = OrderUtil.dateToTimestampT(DateUtil.beginOfDay(DateUtil.
                yesterday()));
        int lastWeek = OrderUtil.dateToTimestampT(DateUtil.beginOfDay(DateUtil.lastWeek()));
        int nowMonth = OrderUtil.dateToTimestampT(DateUtil
                .beginOfMonth(new Date()));
        OrderTimeDataDTO orderTimeDataDTO = new OrderTimeDataDTO();

        orderTimeDataDTO.setTodayCount(pushMallStoreOrderRepository.countByPayTimeGreaterThanEqual(today));
        //orderTimeDataDTO.setTodayPrice(pushMallStoreOrderRepository.sumPrice(today));

        orderTimeDataDTO.setProCount(pushMallStoreOrderRepository
                .countByPayTimeLessThanAndPayTimeGreaterThanEqual(today, yesterday));
        //orderTimeDataDTO.setProPrice(pushMallStoreOrderRepository.sumTPrice(today,yesterday));

        orderTimeDataDTO.setLastWeekCount(pushMallStoreOrderRepository.countByPayTimeGreaterThanEqual(lastWeek));
        //orderTimeDataDTO.setLastWeekPrice(pushMallStoreOrderRepository.sumPrice(lastWeek));

        orderTimeDataDTO.setMonthCount(pushMallStoreOrderRepository.countByPayTimeGreaterThanEqual(nowMonth));
        //orderTimeDataDTO.setMonthPrice(pushMallStoreOrderRepository.sumPrice(nowMonth));

        orderTimeDataDTO.setUserCount(userRepository.count());
        orderTimeDataDTO.setOrderCount(pushMallStoreOrderRepository.count());
        orderTimeDataDTO.setPriceCount(pushMallStoreOrderRepository.sumTotalPrice());
        orderTimeDataDTO.setGoodsCount(storeProductRepository.count());

        return orderTimeDataDTO;
    }

    @Override
    public Map<String, Object> chartCount() {
        Map<String, Object> map = new LinkedHashMap<>();
        int nowMonth = OrderUtil.dateToTimestampT(DateUtil
                .beginOfMonth(new Date()));

        map.put("chart", pushMallStoreOrderRepository.chartList(nowMonth));
        map.put("chartT", pushMallStoreOrderRepository.chartListT(nowMonth));

        return map;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void refund(PushMallStoreOrder resources) {
        if (resources.getPayPrice().doubleValue() < 0) {
            throw new BadRequestException("请输入退款金额");
        }

        if (resources.getPayType().equals("yue")) {
            //修改状态
            resources.setRefundStatus(2);
            resources.setRefundPrice(resources.getPayPrice());
            update(resources);

            //退款到余额
            PushMallUserDTO userDTO = userService.findById(resources.getUid());
            userRepository.updateMoney(resources.getPayPrice().doubleValue(),
                    resources.getUid());

            PushMallUserBill userBill = new PushMallUserBill();
            userBill.setUid(resources.getUid());

            userBill.setLinkId(resources.getId().toString());
            userBill.setPm(1);
            userBill.setTitle("商品退款");
            userBill.setCategory("now_money");
            userBill.setType("pay_product_refund");
            userBill.setNumber(resources.getPayPrice());
            userBill.setBalance(NumberUtil.add(resources.getPayPrice(), userDTO.getNowMoney()));
            userBill.setMark("订单退款到余额");
            userBill.setAddTime(OrderUtil.getSecondTimestampTwo());
            userBill.setStatus(1);
            pushMallUserBillService.create(userBill);


            PushMallStoreOrderStatus storeOrderStatus = new PushMallStoreOrderStatus();
            storeOrderStatus.setOid(resources.getId());
            storeOrderStatus.setChangeType("refund_price");
            storeOrderStatus.setChangeMessage("退款给用户：" + resources.getPayPrice() + "元");
            storeOrderStatus.setChangeTime(OrderUtil.getSecondTimestampTwo());

            pushMallStoreOrderStatusService.create(storeOrderStatus);
        } else {
            BigDecimal bigDecimal = new BigDecimal("100");
            try {
                if (OrderInfoEnum.PAY_CHANNEL_1.getValue().equals(resources.getIsChannel())) {
                    miniPayService.refundOrder(resources.getOrderId(),
                            bigDecimal.multiply(resources.getPayPrice()).intValue());
                } else {
                    payService.refundOrder(resources.getOrderId(),
                            bigDecimal.multiply(resources.getPayPrice()).intValue());
                }

            } catch (WxPayException e) {
                log.info("refund-error:{}", e.getMessage());
            }

        }


    }

    @Override
    public String orderType(int id, int pinkId, int combinationId, int seckillId,
                            int bargainId, int shippingType) {
        String str = "[普通订单]";
        if (pinkId > 0 || combinationId > 0) {
            PushMallStorePink storePink = storePinkRepository.findByOrderIdKey(id);
            if (ObjectUtil.isNull(storePink)) {
                str = "[拼团订单]";
            } else {
                switch (storePink.getStatus()) {
                    case 1:
                        str = "[拼团订单]正在进行中";
                        break;
                    case 2:
                        str = "[拼团订单]已完成";
                        break;
                    case 3:
                        str = "[拼团订单]未完成";
                        break;
                    default:
                        str = "[拼团订单]历史订单";
                        break;
                }
            }

        } else if (seckillId > 0) {
            str = "[秒杀订单]";
        } else if (bargainId > 0) {
            str = "[砍价订单]";
        }
        if (shippingType == 2) {
            str = "[核销订单]";
        }
        return str;
    }

    public List<PushMallStoreOrderDTO> manageList(List<PushMallStoreOrder> content) {
        List<PushMallStoreOrderDTO> storeOrderDTOS = new ArrayList<>();
        for (PushMallStoreOrder pushMallStoreOrder : content) {
            PushMallStoreOrderDTO pushMallStoreOrderDTO = pushMallStoreOrderMapper.toDto(pushMallStoreOrder);

            Integer _status = OrderUtil.orderStatus(pushMallStoreOrder.getPaid(), pushMallStoreOrder.getStatus(),
                    pushMallStoreOrder.getRefundStatus());

            if (pushMallStoreOrder.getStoreId() > 0) {
                String storeName = systemStoreService.findById(pushMallStoreOrder.getStoreId()).getName();
                pushMallStoreOrderDTO.setStoreName(storeName);
            }

            //订单状态
            String orderStatusStr = OrderUtil.orderStatusStr(pushMallStoreOrder.getPaid()
                    , pushMallStoreOrder.getStatus(), pushMallStoreOrder.getShippingType()
                    , pushMallStoreOrder.getRefundStatus());

            if (_status == 3) {
                String refundTime = OrderUtil.stampToDate(String.valueOf(pushMallStoreOrder
                        .getRefundReasonTime()));
                String str = "<b style='color:#f124c7'>申请退款</b><br/>" +
                        "<span>退款原因：" + pushMallStoreOrder.getRefundReasonWap() + "</span><br/>" +
                        "<span>备注说明：" + pushMallStoreOrder.getRefundReasonWapExplain() + "</span><br/>" +
                        "<span>退款时间：" + refundTime + "</span><br/>";
                orderStatusStr = str;
            }
            pushMallStoreOrderDTO.setStatusName(orderStatusStr);

            pushMallStoreOrderDTO.set_status(_status);

            String payTypeName = OrderUtil.payTypeName(pushMallStoreOrder.getPayType()
                    , pushMallStoreOrder.getPaid());
            pushMallStoreOrderDTO.setPayTypeName(payTypeName);

            pushMallStoreOrderDTO.setPinkName(orderType(pushMallStoreOrder.getId()
                    , pushMallStoreOrder.getPinkId(), pushMallStoreOrder.getCombinationId()
                    , pushMallStoreOrder.getSeckillId(), pushMallStoreOrder.getBargainId(),
                    pushMallStoreOrder.getShippingType()));

            List<StoreOrderCartInfo> cartInfos = pushMallStoreOrderCartInfoRepository
                    .findByOid(pushMallStoreOrder.getId());
            List<StoreOrderCartInfoDTO> cartInfoDTOS = new ArrayList<>();
            for (StoreOrderCartInfo cartInfo : cartInfos) {
                StoreOrderCartInfoDTO cartInfoDTO = new StoreOrderCartInfoDTO();
                cartInfoDTO.setId(cartInfo.getId());
                cartInfoDTO.setCartId(cartInfo.getCartId());
                cartInfoDTO.setOid(cartInfo.getOid());
                cartInfoDTO.setUnique(cartInfo.getUnique());

                JSONObject jsonObject = JSON.parseObject(cartInfo.getCartInfo());
                PushMallStoreProductAttrValue pushMallStoreProductAttrValue = new PushMallStoreProductAttrValue();
                if (!ObjectUtils.isEmpty(jsonObject.get("productAttrUnique"))) {
                    pushMallStoreProductAttrValue = pushMallStoreProductAttrValueRepository
                            .findbyUnique(jsonObject.get("productAttrUnique").toString());
                }
                JSONObject jsonObject1 = new JSONObject();
                if (!ObjectUtils.isEmpty(pushMallStoreProductAttrValue)) {
                    jsonObject1 = JSONObject.parseObject(JSONObject.toJSONString(pushMallStoreProductAttrValue));
                }
                cartInfoDTO.setCartInfoMap(jsonObject);
                cartInfoDTO.setAttrInfoMap(jsonObject1);

                cartInfoDTOS.add(cartInfoDTO);
            }
            pushMallStoreOrderDTO.setCartInfoList(cartInfoDTOS);
            pushMallStoreOrderDTO.setUserDTO(userService.findById(pushMallStoreOrder.getUid()));

            storeOrderDTOS.add(pushMallStoreOrderDTO);
        }

       /* Map<String,Object> map = new LinkedHashMap<>(2);
        map.put("content",storeOrderDTOS);
        map.put("totalElements",page.getTotalElements());*/
        return storeOrderDTOS;
    }

    @Override
    public Map<String, Object> queryAll(PushMallStoreOrderQueryCriteria criteria, Pageable pageable) {

        Page<PushMallStoreOrder> page = pushMallStoreOrderRepository
                .findAll((root, criteriaQuery, criteriaBuilder)
                        -> QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable);
        List<PushMallStoreOrderDTO> storeOrderDTOS = new ArrayList<>();
        storeOrderDTOS = manageList(page.getContent());

        Map<String, Object> map = new LinkedHashMap<>(2);
        map.put("content", storeOrderDTOS);
        map.put("totalElements", page.getTotalElements());
        return map;
    }

    @Override
    public List<PushMallStoreOrderDTO> queryAll(PushMallStoreOrderQueryCriteria criteria) {
        return pushMallStoreOrderMapper.toDto(pushMallStoreOrderRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder)));
    }

    @Override
    public PushMallStoreOrderDTO findById(Integer id) {
        Optional<PushMallStoreOrder> yxStoreOrder = pushMallStoreOrderRepository.findById(id);
        //ValidationUtil.isNull(yxStoreOrder,"PushMallStoreOrder","id",id);
        if (yxStoreOrder.isPresent()) {
            return pushMallStoreOrderMapper.toDto(yxStoreOrder.get());
        }
        return new PushMallStoreOrderDTO();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PushMallStoreOrderDTO create(PushMallStoreOrder resources) {
        if (pushMallStoreOrderRepository.findByUnique(resources.getUnique()) != null) {
            throw new EntityExistException(PushMallStoreOrder.class, "unique", resources.getUnique());
        }
        return pushMallStoreOrderMapper.toDto(pushMallStoreOrderRepository.save(resources));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(PushMallStoreOrder resources) {
        Optional<PushMallStoreOrder> optionalPushMallStoreOrder = pushMallStoreOrderRepository.findById(resources.getId());
        ValidationUtil.isNull(optionalPushMallStoreOrder, "PushMallStoreOrder", "id", resources.getId());
        PushMallStoreOrder pushMallStoreOrder = optionalPushMallStoreOrder.get();
        PushMallStoreOrder pushMallStoreOrder1 = pushMallStoreOrderRepository.findByUnique(resources.getUnique());
        if (pushMallStoreOrder1 != null && !pushMallStoreOrder1.getId().equals(pushMallStoreOrder.getId())) {
            throw new EntityExistException(PushMallStoreOrder.class, "unique", resources.getUnique());
        }
        pushMallStoreOrder.copy(resources);
        pushMallStoreOrderRepository.save(pushMallStoreOrder);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Integer id) {
        pushMallStoreOrderRepository.deleteById(id);
    }

    /**
     * 导出订单数据
     *
     * @param queryAll
     * @param response
     * @throws IOException
     * @throws ParseException
     */
    @Override
    public void download(List<PushMallStoreOrderDTO> queryAll, HttpServletResponse response) throws IOException, ParseException {
        List<Map<String, Object>> list = new ArrayList<>();

        for (PushMallStoreOrderDTO storeOrderDTO : queryAll) {
            List<StoreOrderCartInfoDTO> storeList = storeOrderDTO.getCartInfoList();
            if (storeList != null) {
                for (StoreOrderCartInfoDTO storeOrderCartInfoDTO : storeList) {
                    Map<String, Object> map = new LinkedHashMap<>();
                    Map proInfo = ((Map) storeOrderCartInfoDTO.getCartInfoMap().get("productInfo"));
                    Map cartInfo = storeOrderCartInfoDTO.getCartInfoMap();
                    Map attrInfo = storeOrderCartInfoDTO.getAttrInfoMap();
                    map.put("订单号", storeOrderDTO.getOrderId());
                    map.put("下单时间", OrderUtil.stampToDate(storeOrderDTO.getAddTime() + ""));

                    map.put("客户编号", storeOrderDTO.getUserDTO().getAccount());
                    map.put("客户名称", storeOrderDTO.getUserDTO().getNickname());
                    map.put("客户类型", storeOrderDTO.getUserDTO().getUserType());
                    map.put("客户手机号码", storeOrderDTO.getUserDTO().getPhone() + '/' + storeOrderDTO.getUserDTO().getTelephone());
                    map.put("是否为推广员", storeOrderDTO.getUserDTO().getIsPromoter());

                    map.put("收货人", storeOrderDTO.getRealName());
                    map.put("联系电话", storeOrderDTO.getUserPhone());
                    map.put("收货地址", storeOrderDTO.getUserAddress());

                    String price = cartInfo.get("truePrice") == null ? "0.00" : cartInfo.get("truePrice").toString();
                    String salse = cartInfo.get("cartNum") == null ? "0" : cartInfo.get("cartNum").toString();
                    BigDecimal postage = storeOrderDTO.getPayPostage() == null ? new BigDecimal(0.00) : storeOrderDTO.getPayPostage();
                    BigDecimal total = new BigDecimal(price).multiply(new BigDecimal(salse));
                    BigDecimal totalNum = new BigDecimal(total.toString()).add(new BigDecimal(postage.toString()));
                    map.put("商品编号", proInfo.get("id"));
                    map.put("商品名称", proInfo.get("storeName"));
                    map.put("商品规格", attrInfo.get("packaging"));
                    map.put("商品库存", cartInfo.get("trueStock"));

                    map.put("订单状态", storeOrderDTO.getStatusName());
                    map.put("支付状态", storeOrderDTO.getPayTypeName());
                    map.put("单价", price);
                    map.put("订购数量", salse);
                    map.put("小计", total);
                    map.put("配送费用", storeOrderDTO.getPayPostage());
                    map.put("总计", totalNum);
                    map.put("订单备注", storeOrderDTO.getMark());

                    list.add(map);
                }
            }
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public List<PushMallStoreOrderDTO> findByIds(List<String> idList) {
        List<PushMallStoreOrder> byIds = pushMallStoreOrderRepository.findByIds(idList);
        List<PushMallStoreOrderDTO> pushMallStoreOrderDTOS = manageList(byIds);
        return pushMallStoreOrderDTOS;
    }
}
